#include <system.h>
#include <network/network.h>
/**************************************************************//*
Interface Network{
	Provides{
		command void NETWORK_init();
		command void NETWORK_reg(void(*startDone)(error_t),
								 void(*sendDone)(error_t),
								 message_t *(*)(message_t*,uint8_t*,uint16_t));
		command error_t NETWORK_start();
		command error_t NETWORK_send(uint16_t dest,message_t*,uint16_t len,uint8_t type);
	}
	Uses{
		signal void (*netstartdone)(error_t);
		signal void (*netsenddone)(error_t);
		signal message_t* (*netreceive)(message_t*,uint8_t*,uint16_t);
	}
}*/
/***************************************************************/
/*
MODULE NETWORK uses MODULE XBEE interface
	call{
		XBEE_start();
		XBEE_reg(void(*startDone)(error_t),
						 void(*transmitDone)(error_t),
		                 message_t*(*receive)(message_t*,void*msg,uint8_t len));
		XBEE_send(uint16_t destAddr,void*msg,uint8_t len);	
	}
	event{
		void xbeestartdone(error_t);
		void xbeesenddone(error_t);
		message_t *xbeereceive(message_t*,void*,uint8_t len);
	}
*/	

//PRIVATE
	//Data Field
	enum{
		RECV_BUFF_SIZE = 10,
		NET_HISTORY = 4,

		NET_STOPPED,
		NET_IDLE,
		NET_SENDING,
		NET_REBCAST,
	};

	task_t networkrecv;

	struct{
		uint8_t state;
		uint8_t seq;
		uint8_t rxFull;
		uint8_t rxIn;
		uint8_t rxOut;
		uint8_t rxBusy;
	}net;

	struct{
		message_t buff;
		message_t* p_buff;
		uint8_t len;
	}recv_buff[RECV_BUFF_SIZE];

	struct{
		uint8_t seq;
		uint16_t src;
	}history[NET_HISTORY];

	//Function Member
	void (*netstartdone)(error_t);
	void (*netsenddone)(error_t);
	message_t* (*netreceive)(message_t*,uint8_t*,uint16_t);

	void network_recv(void);

	void xbeestartdone(error_t);
	void xbeesenddone(error_t);

	message_t *xbeereceive(message_t*,void*,uint8_t len);
	error_t check_duplicate(message_t* duplicate,uint16_t src,uint8_t seq);

	void netDefaultStartDone(error_t);
	void netDefaultSendDone(error_t);

	message_t *netDefaultReceive(message_t*,uint8_t*, uint16_t);

/**************************************************************/
/*            Client Function Implementation                  */
/*                      (Provides)                            */					
/**************************************************************/
void NETWORK_reg(void(*startDone)(error_t),void(*sendDone)(error_t),message_t*(*receive)(message_t*,uint8_t*,uint16_t)){
	netstartdone = startDone;
	netsenddone  = sendDone;
	netreceive	 = receive;
}

error_t NETWORK_start(void){
	if(net.state != NET_STOPPED)
		return FAIL;
	net.state = NET_IDLE;	

	XBEE_reg(xbeestartdone,xbeesenddone,xbeereceive);
	TASK_reg(&networkrecv,network_recv);
	
	return XBEE_start();
}

error_t NETWORK_send(uint16_t dest,message_t* packet_send,uint16_t len,uint8_t type){

	msg_header_t* header = (msg_header_t*)(packet_send->header);
	
	

	if(net.state != NET_IDLE)
		return FAIL;
	net.state = NET_SENDING;

	//SET NETWORK SOURCE ADDRESS
	header->src[0] = (uint8_t)(NET_SRC_ADD>>8);
	header->src[1] = (uint8_t)(NET_SRC_ADD);
	//SET NETWORK DEST ADD
	header->dest[0] = (uint8_t)(dest>>8);
	header->dest[1] = (uint8_t)(dest);
	//SET MESSAGE LENGTH
	header->len[0] = (uint8_t)(len>>8);
	header->len[1] = (uint8_t)(len);
	//SET MESSAGE SEQUENCE NUMBER
	header->seq = net.seq++;
	//SET MESSAGE DATA TYPE
	header->type = type;
	//SET MAX MESSAGE HOPPING
	header->hop = MAX_HOP;
	
	LED0_toggle();

	return XBEE_send(MAC_DEST_ADD,packet_send,len+sizeof(msg_header_t));
}
/**************************************************************/
/*            Private Function Implementation                 */
/*                      (Internals)                           */					
/**************************************************************/
void network_recv(void){

	uint16_t dest,len,src;
	uint8_t seq;
	
	message_t* app_msg;

	uint8_t sreg = SREG;
	cli();

	if(net.rxIn==net.rxOut && !net.rxFull){
		SREG = sreg;
		return;
	}

	app_msg = recv_buff[net.rxOut].p_buff;
	msg_header_t* header = (msg_header_t*)(app_msg->header);
	
	//FETCH NETWORK SRC ADD
	src  = header->src[0];
	src <<=8;
	src |= header->src[1];
	//FETCH NETWORK DEST ADD
	dest = header->dest[0];
	dest <<=8;
	dest |= header->dest[1];
	//FETCH MESSAGE PAYLOAD LENGTH
	len = header->len[0];
	len <<= 8;
	len |= header->len[1];
	//FETCH MESSAGE SEQUENCE NUMBER
	seq = header->seq;

	SREG = sreg;

	if(check_duplicate(app_msg,src,seq)==SUCCESS){
		if(dest==MAC_SRC_ADD || dest==NET_BROADCAST){
			app_msg = (*netreceive)(app_msg,app_msg->payload,len);
			
		}
		else{
			if(net.state==NET_IDLE){
				uint8_t hop = header->hop;
				if(hop>0){
					hop--;
					header->hop = hop;

					net.state = NET_REBCAST;
					XBEE_send(MAC_DEST_ADD,app_msg,len+sizeof(msg_header_t));
					return;
				}
			}
		}
	}

	SREG = sreg;
	cli();

	net.rxOut = (net.rxOut +1)%RECV_BUFF_SIZE;
	net.rxFull = 0;
	
	SREG = sreg;
	TASK_post(&networkrecv);
}

error_t check_duplicate(message_t* duplicate,uint16_t src,uint8_t seq){
	uint8_t i;

	if(src==NODE_ID)
		return FAIL;

	for(i=0; i<NET_HISTORY;i++){
		if(src==history[i].src){
			if(seq==history[i].seq){
				return FAIL;
			}
			else{
				history[i].seq = seq;
				return SUCCESS;
			}
		}
		if(history[i].src==NET_BROADCAST){
			history[i].src = src;
			history[i].seq = seq;
			return SUCCESS;
		}
	}


return FAIL;
}

void netDefaultStartDone(error_t err){
}

void netDefaultSendDone(error_t err){
}

message_t *netDefaultReceive(message_t* msg,uint8_t* def_msg,uint16_t def_len){
	return msg;
}
/**************************************************************/
/*            System Function Implementation                  */
/*                    (Used by system)                        */					
/**************************************************************/
void NETWORK_init(){

	uint8_t i,j;

	net.state = NET_STOPPED;
	net.seq = 0;

	net.rxFull = net.rxIn = net.rxOut = net.rxBusy = 0;

	for(i=0;i<RECV_BUFF_SIZE;i++){
		recv_buff[i].p_buff = &(recv_buff[i].buff);
	}

	for(j=0;j<NET_HISTORY;j++){
		history[j].src = NET_BROADCAST;
		history[j].seq = 0;
	}

	netstartdone = netDefaultStartDone;
	netsenddone  = netDefaultSendDone;
	netreceive	 = netDefaultReceive;
}

void xbeestartdone(error_t err){
    (*netstartdone)(SUCCESS);
}

void xbeesenddone(error_t err){
	if(net.state==NET_REBCAST){
		uint8_t sreg = SREG;
		cli();

		net.state = NET_IDLE;

		net.rxOut = (net.rxOut + 1)%RECV_BUFF_SIZE;
		net.rxFull = 0;

		SREG = sreg;
		TASK_post(&networkrecv);
	}
	
	net.state = NET_IDLE;
	(*netsenddone)(err); 
}

message_t *xbeereceive(message_t* api,void* api_payload,uint8_t len){

	message_t* ret = api;
	
	

	if(net.rxFull)
		return ret;
	
	ret = recv_buff[net.rxIn].p_buff;
	recv_buff[net.rxIn].p_buff = api;

	net.rxIn = (net.rxIn+1)%RECV_BUFF_SIZE;

	if(net.rxIn==net.rxOut)
		net.rxFull=1;

	if(!net.rxBusy){
		TASK_post(&networkrecv);
	}
	
	return ret;	
}
